package websocket

import (
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

// 连接限制常量
const (
	maxConcurrentConnections = 1000
	connectionTimeout        = 10 * time.Second
)

var (
	connectionSemaphore = make(chan struct{}, maxConcurrentConnections)
	activeConnections   sync.Map
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true // 允许所有来源，生产环境中应该进行适当的验证
	},
}

// Handler 创建一个新的 WebSocket 处理器
func Handler(config *Config) gin.HandlerFunc {
	if config == nil {
		config = DefaultConfig()
	}

	hub := NewHub(config)
	go hub.Run()

	// 添加连接统计
	go monitorConnections(hub)

	return func(c *gin.Context) {
		// 升级HTTP连接为WebSocket连接
		conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
		if err != nil {
			log.Printf("Failed to upgrade connection: %v", err)
			c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to upgrade connection"})
			return
		}

		handleWebSocketConnection(conn, hub, config, c)
	}
}

// monitorConnections 监控连接数量
func monitorConnections(hub *Hub) {
	ticker := time.NewTicker(time.Minute)
	defer ticker.Stop()

	for range ticker.C {
		stats := hub.Stats()
		log.Printf("WebSocket Stats - Total Clients: %d, Total Rooms: %d",
			stats["total_clients"], stats["total_rooms"])
	}
}

// handleWebSocketConnection 处理WebSocket连接
func handleWebSocketConnection(conn *websocket.Conn, hub *Hub, config *Config, c *gin.Context) {
	// 使用带超时的信号量获取
	timeout := time.NewTimer(connectionTimeout)
	defer timeout.Stop()

	select {
	case connectionSemaphore <- struct{}{}:
		defer func() { <-connectionSemaphore }()
	case <-timeout.C:
		_ = conn.WriteJSON(Message{
			Type:  TextMessage,
			Event: "error",
			Error: "connection limit reached",
			Time:  time.Now(),
		})
		_ = conn.Close()
		if config.ErrorHandler != nil {
			config.ErrorHandler.HandleError(nil, fmt.Errorf("connection limit reached"))
		}
		return
	}

	// 验证客户端
	if !authenticateClient(conn, config, c) {
		return
	}

	client := NewClient(conn, hub)
	activeConnections.Store(client.ID, client)

	// 确保在函数返回时清理资源
	defer func() {
		activeConnections.Delete(client.ID)
		if r := recover(); r != nil {
			log.Printf("WebSocket handler panic recovered: %v", r)
			if config.ErrorHandler != nil {
				config.ErrorHandler.HandleError(client, fmt.Errorf("handler panic: %v", r))
			}
		}
	}()

	// 注册客户端
	hub.register <- client

	// 启动读写协程
	done := make(chan struct{})
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("WritePump panic recovered: %v", r)
			}
			close(done)
		}()
		client.WritePump()
	}()

	client.ReadPump()
	<-done // 等待写入协程完成
}

// authenticateClient 认证客户端
func authenticateClient(conn *websocket.Conn, config *Config, c *gin.Context) bool {
	if config.AuthHandler == nil {
		return true
	}

	authChan := make(chan bool, 1)
	timeout := time.After(5 * time.Second)

	go func() {
		params := make(map[string]interface{})
		// 从 Gin 上下文中获取参数
		for key, value := range c.Request.URL.Query() {
			if len(value) > 0 {
				params[key] = value[0]
			}
		}
		// 添加 headers
		for key, value := range c.Request.Header {
			if len(value) > 0 {
				params["header_"+key] = value[0]
			}
		}

		_, err := config.AuthHandler.Authenticate(params)
		authChan <- err == nil
	}()

	select {
	case isAuthenticated := <-authChan:
		if !isAuthenticated {
			_ = conn.WriteJSON(Message{
				Type:  TextMessage,
				Event: "error",
				Error: "unauthorized",
				Time:  time.Now(),
			})
			_ = conn.Close()
		}
		return isAuthenticated
	case <-timeout:
		_ = conn.WriteJSON(Message{
			Type:  TextMessage,
			Event: "error",
			Error: "authentication timeout",
			Time:  time.Now(),
		})
		_ = conn.Close()
		return false
	}
}

// GetActiveConnections 获取当前活跃连接数
func GetActiveConnections() int {
	count := 0
	activeConnections.Range(func(_, _ interface{}) bool {
		count++
		return true
	})
	return count
}

// UpgradeMiddleware WebSocket升级中间件
func UpgradeMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if isWebSocketUpgrade(c.Request) {
			// 检查是否达到最大连接数
			if GetActiveConnections() >= maxConcurrentConnections {
				c.JSON(http.StatusServiceUnavailable, gin.H{"error": "connection limit reached"})
				c.Abort()
				return
			}
			c.Set("allowed", true)
			c.Next()
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Upgrade required"})
			c.Abort()
		}
	}
}

// isWebSocketUpgrade 检查请求是否为WebSocket升级请求
func isWebSocketUpgrade(r *http.Request) bool {
	return r.Header.Get("Upgrade") == "websocket" && r.Header.Get("Connection") == "Upgrade"
}
